﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Lucene.Net.Store;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;
using Lucene.Net.Analysis.Standard;
using System.Collections;
using Lucene.Net.Index;

namespace Universum.Model.Services.Indexing
{
	public class LuceneSearchIndex : IDisposable
	{
		/// <summary>
		/// The index directory used for search
		/// </summary>
		private Directory _IndexDirectory;
		/// <summary>
		/// Creates a new search index
		/// </summary>
		/// <param name="directoryPath">The path where to search</param>
		public LuceneSearchIndex(string directoryPath)
		{
			_IndexDirectory = FSDirectory.GetDirectory(directoryPath, null);
			_IndexDirectory.SetLockFactory(new NoLockFactory());
		}
		/// <summary>
		/// Creates a new search index
		/// </summary>
		/// <param name="directory">The directory where to search</param>
		public LuceneSearchIndex(Directory directory)
		{
			_IndexDirectory = directory;
		}
		/// <summary>
		/// Searches the index based on the query,
		/// and optionally the filter
		/// </summary>
		/// <param name="query">The text query</param>
		/// <param name="keywordFilter">The keywords to filter for</param>
		/// <returns>Returns the hit results</returns>
		public Hits Find(
			string query,
			Hashtable keywordFilter
			)
		{
			
			Hits hits;
			
			BooleanQuery mainQuery = new BooleanQuery();
			Query multiQuery = MultiFieldQueryParser.Parse(
				new string[] { query, query },
				new string[] { "Title", "Text" },
				new StandardAnalyzer());
			mainQuery.Add(multiQuery, BooleanClause.Occur.MUST);
			

			if (keywordFilter != null && keywordFilter.Count > 0)
			{
				QueryFilter qf = BuildQueryFilterFromKeywordFilter(keywordFilter);
				hits = Find(mainQuery, qf);
			}
			else
			{
				hits = Find(mainQuery); //searcher.Search(mainQuery);
			}

			return hits;


		}
		/// <summary>
		/// Gets the hits on the index directory using the query
		/// </summary>
		/// <param name="luceneQuery">The lucene query</param>
		/// <returns>Returns the hits found</returns>
		public Hits Find(Query luceneQuery)
		{
			return Find(luceneQuery, null);
		}
		/// <summary>
		/// Gets the hits for a certain query and it's filter
		/// </summary>
		/// <param name="luceneQuery">The lucene query</param>
		/// <param name="filter">The lucene filter</param>
		/// <returns>Returns the hits of the query filtered by filter</returns>
		public Hits Find(Query luceneQuery, Filter filter)
		{
			IndexSearcher searcher = new IndexSearcher(_IndexDirectory);
			if (filter != null)
			{
				return searcher.Search(luceneQuery, filter);
			}
			else
				return searcher.Search(luceneQuery);
		}

		private QueryFilter BuildQueryFilterFromKeywordFilter(Hashtable keywordFilter)
		{
			BooleanQuery bQuery = new BooleanQuery();
			foreach (DictionaryEntry keywordFilterTerm in keywordFilter)
			{
				string field = keywordFilterTerm.Key.ToString();
				string keyword = keywordFilterTerm.Value.ToString();
				bQuery.Add(new TermQuery(new Term(field, keyword)), BooleanClause.Occur.MUST);
			}

			return new QueryFilter(bQuery);
		}

		#region IDisposable Members

		public void Dispose()
		{
			Close();
		}

		private void Close()
		{
			_IndexDirectory.Close();
		}

		#endregion
	}
}
